在現代動態設計中,過程的流暢性往往比最終的結果更能吸引使用者的目光。
Vue 的過渡類別不僅能幫助我們設計出精美的動效,更能將每一個動作細膩地表現出來,讓動態不再僅僅是視覺上的變化,而是充滿韻律與故事感的藝術。
為什麼過渡類別如此重要?
過渡類別可以讓元素的進場和離場變得更自然且引人入勝,不僅是設計的點綴,更是使用者體驗的升級。
例如在商業網站中,產品展示、創意作品集等應用場景,這些過渡效果都能讓頁面切換更順暢,並增添整體的精緻感,增加瀏覽率。
Page Transition 滑頁效果是現代網站中不可或缺的過渡技巧之一。
無論是產品展示、電商平台還是創意作品集,這些過渡類別總是能在關鍵時刻出現,讓頁面切換更順。
當用得恰到好處,不僅讓畫面更靈動,還能給人一種高質感的視覺享受!
檔案架構
首先是PageTransition.vue
父元件
PageTransitionStart.vue
PageTransitionNext.vue
PageTransitionEnd.vue
,再下一頁會回到第一頁主要程式碼(PageTransition.vue)
<script lang="ts" setup>
import { shallowRef, computed, defineAsyncComponent } from 'vue';
// 定義我們的每頁component
enum Pages {
Start = 'start',
Next = 'next',
End = 'end', // 新增頁面作為示例
}
// 定義頁面元件與背景顏色的配置
const pageConfig = {
[Pages.Start]: {
component: defineAsyncComponent(() => import('./PageTransitionStart.vue')),
color: 'bg-[#f1c40f]'
},
[Pages.Next]: {
component: defineAsyncComponent(() => import('./PageTransitionNext.vue')),
color: 'bg-[#e67e22]'
},
[Pages.End]: {
component: defineAsyncComponent(() => import('./PageTransitionEnd.vue')),
color: 'bg-green-300'
}
};
const page = shallowRef(Pages.Start);
// 使用 pageConfig 獲取對應的元件和背景顏色
const getComponent = computed(() => pageConfig[page.value].component);
const containerBgColor = computed(() => pageConfig[page.value].color);
const changePage = (newPage: Pages) => {
page.value = newPage;
};
</script>
<template>
<div :class="['relative w-full h-screen overflow-hidden', containerBgColor]">
<transition name="slide" mode="out-in">
<component :is="getComponent" @change-page="changePage" />
</transition>
</div>
</template>
<style scoped>
.slide-enter-from {
transform: translateX(100%);
}
.slide-enter-active, .slide-leave-active {
position: absolute;
width: 100%;
transition: transform 0.5s ease;
}
.slide-leave-to {
transform: translateX(-100%);
}
.slide-enter-to, .slide-leave-from {
transform: translateX(0);
}
</style>
<style scoped>
.slide-enter-from {
transform: translateX(100%);
}
.slide-enter-active, .slide-leave-active {
position: absolute;
width: 100%;
transition: transform 0.5s ease;
}
.slide-leave-to {
transform: translateX(-100%);
}
.slide-enter-to, .slide-leave-from {
transform: translateX(0);
}
</style>
進場流程
元素從右側滑入 (slide-enter-from
) → 過渡過程中保持絕對位置與寬度 (slide-enter-active
) → 最終到達正中位置 (slide-enter-to
)。
離場流程
元素從正中開始 元素從正中開始 (slide-leave-from
) → 過渡過程中保持絕對位置與寬度 (slide-leave-active
) → 最後滑出到左側 (slide-leave-to
)
PageTransitionStart.vue
<script lang="ts" setup>
//定義事件 defineEmits
const emit = defineEmits(['change-page']);
</script>
<template>
<transition name="slide">
<div class="grid w-full grid-cols-[repeat(auto-fit,_minmax(400px,_1fr))]">
<transition name="fade">
<div
class="grid h-screen items-center justify-center bg-[var(--bg-color)]"
:style="{ '--bg-color': '#f1c40f' }"
>
// 換頁方法
// 當按鈕被點擊時,`@click` 會監聽到這個事件並執行 `emit('change-page', 'next')`
<button
@click="emit('change-page', 'next')"
class="btn-jittery text-8 font-mono bg-transparent
text-white
border-3 border-solid border-white rounded-full px-8 py-3
outline-none cursor-pointer tracking-[2px]
animate-[jittery_4s_infinite] hover:animate-[heartbeat_0.2s_infinite]
"
>
Start !
</button>
</div>
</transition>
</div>
</transition>
</template>
<style>
/* Vue Transition Styles */
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s ease-in-out;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
@keyframes jittery {
0%, 50% { transform: scale(1); }
10% { transform: scale(0.9); }
15% { transform: scale(1.15); }
20% { transform: scale(1.15) rotate(-5deg); }
25% { transform: scale(1.15) rotate(5deg); }
30% { transform: scale(1.15) rotate(-3deg); }
35% { transform: scale(1.15) rotate(2deg); }
40% { transform: scale(1.15) rotate(0); }
}
@keyframes heartbeat {
50% {
transform: scale(1.1);
}
}
</style>
PageTransitionNext.vue
//.... 其他重複先省略
<transition name="fade">
<div
class="grid h-screen items-center justify-center bg-[var(--bg-color)]"
:style="{ '--bg-color': '#e67e22' }"
>
<button
@click="emit('change-page', 'start')"
class="btn-jittery text-8 font-mono bg-transparent
text-white
border-3 border-solid border-white rounded-full px-8 py-3
outline-none cursor-pointer tracking-[2px]
animate-[jittery_4s_infinite] hover:animate-[heartbeat_0.2s_infinite]
"
>
End !
</button>
</div>
</transition>
//....
PageTransitionEnd.vue
//....與前面兩頁一樣,僅提供差異處
// 定義此頁背景色
<div class="grid h-screen items-center justify-center bg-[var(--bg-color)]"
:style="{ '--bg-color': '#e67e22' }"
>
// emit('change-page','start') 帶入第一頁參數,下一頁就又回到第一頁了
<button @click="emit('change-page', 'start')" class="..."></button>
Vue 的過渡類別的執行過程,主要應用於 初始化與加載 和 結尾與退出 這兩個核心階段。
中間的 瀏覽與互動階段 會使用 CSS 動畫(@keyframes
)或是JavaScript、GSAP等等來進行。
進場動效順序
v-enter-from
→ v-enter-active
→ v-enter-to
離場動效順序
v-leave-from
→ v-leave-active
→ v-leave-to
v-enter-from
前面的v
就是我們自定義的class名稱。
進場動效
初始化開始
v-enter-from
:元素剛插入時的初始狀態(通常是隱藏的狀態)。這是動效的起點,常使用 CSS 設置透明度為 0 或將元素移出視窗範圍。活動狀態
v-enter-active
:進場動效進行中的狀態,從元素插入到動效完成的整個過程。這裡可調整動效的時間、延遲和緩動曲線,例如:transition: all 0.5s ease-in-out;
。動效完成
v-enter-to
:進場動效的結束狀態。這個類別在動效的最後應用,代表元素已完全顯示。離場動效
初始狀態
v-leave-from
:觸發離場動效時的初始狀態(通常是元素顯示的狀態)。應用於動效開始時。活動狀態
v-leave-active
:離場動效進行中的狀態,應用於動效的整個過程中。可設置離場動效的時間、延遲和緩動曲線。動效完成
v-leave-to
:離場動效的結束狀態。這個類別在離場動效的第一幀後應用,並在動效結束時移除,通常代表元素隱藏的狀態。掌握 Vue 過渡類別後,你會發現這不僅僅是動效工具,而是一種設計語言,讓你在網站設計上能有更多創意的表現空間。
希望你能夠將這些過渡類別運用到你的專案中,並持續探索動態設計的無限可能。